/*
 * UpdateFiles.java
 *
 * Created on 22 September 2006, 12:19
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package hubsniffer.sghdc;

import hubsniffer.db.DataBaseManager;
import hubsniffer.db.util.Util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.BatchUpdateException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.Iterator;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.tools.bzip2.CBZip2InputStream;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author root
 */
public class UpdateFiles {
    
    private DataBaseManager db;
    private Stack<libjdc.dc.filelist.File> files;
    public static final FileList all = new FileList(100000);
    
    private void updateFile(String file_name, String file_size, String file_TTH) throws SQLException {
        ResultSet rs = null;
        String message = "SELECT * FROM \"file\" WHERE \"file_name\" LIKE '"+file_name+"' AND \"file_size\"= "+file_size+" AND \"file_TTH\" LIKE '"+file_TTH+"'";
        rs = db.getSql_stm().executeQuery(message);
        
        if (rs.next()) {
            Integer count = new Integer(rs.getString("file_count"));
            updateFile(rs.getString("file_id"),((count==null)? 1 : (count.intValue())+1));
        }
        
        
    }
    
    private void updateFile(String file_id, int file_count) {
        String message = "UPDATE file SET file_count="+file_count+" WHERE file_id="+file_id;
        try {
            db.getSql_stm().executeUpdate(message);
        } catch (SQLException ex) {
            //ex.printStackTrace();
            //System.out.println(message);
        }
    }
    
    public void processFileList(){
        String message;
        Iterator<libjdc.dc.filelist.File> it = files.iterator();
        System.out.println("*** Start writing at DB files:"+files.size());
        while(it.hasNext()){
            libjdc.dc.filelist.File current = it.next();
            message = new String("insert into \"file\" (\"file_name\",\"file_size\",\"file_TTH\",\"file_count\") values ('"+current.getName()+"',"+current.getSize()+",'"+current.getTTH()+"',1)");
                
            try {
                db.writeRawSql(message,true);
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
                System.out.println(message);
            } catch (SQLException ex) {
                //ex.printStackTrace();
                System.out.println("error:"+ message);
                //updateFile(current.getName(),current.getSize(),current.getTTH());
            }
            
            
        }
    }
    
    
    /** Creates a new instance of UpdateFiles */
    public UpdateFiles(DataBaseManager db,Stack<libjdc.dc.filelist.File> files) {
        this.db = db;
        this.files = files;
    }
    
    public static void DBUpdate(DataBaseManager db) throws ClassNotFoundException, SQLException, FileNotFoundException{
        
        Date start = new Date();
        System.out.println("Vai come�ar a ler os ficheiros para escrever na BD: "+start);
        BufferedReader in = new BufferedReader(new FileReader("/home/dbotelho/Filelist.txt"));
        String line;
        
        Statement stmt = db.getSql_stm();
        db.getConn().setAutoCommit(false);
        int count=0;
        try {
            while((line = in.readLine())!= null){
                    stmt.addBatch(line);
                    count++;
                    if(count >= 1000){
                        try{
                            int [] updateCounts = stmt.executeBatch();
                            
                            //System.err.println("");
                            System.out.println("Num de entradas: "+updateCounts.length+" inicio:"+start+" fim:"+new Date());
                            
                            db.getConn().commit();
                            count = 0;
                            System.gc();
                            System.out.println("*** Free Memory (after GC):"+Runtime.getRuntime().freeMemory());
                        }catch(BatchUpdateException b) {
                            b.printStackTrace();
                            
                            b.getNextException().printStackTrace();
                            db.getConn().rollback();
                        }
                    }
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        try {
            in.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        System.out.println("Terminou de ler o ficheiro e vai come�ar a escrever na BD: "+new Date()+" num de stmts:"+count);
        try{
            int [] updateCounts = stmt.executeBatch();
            
            //System.err.println("");
            System.out.println("Num de entradas: "+updateCounts.length+" inicio:"+start+" fim:"+new Date());
            
            db.getConn().commit();
        }catch(BatchUpdateException b) {
            b.printStackTrace();
            b.getNextException().printStackTrace();
            /*System.err.println("Update counts of successful commands: ");
            int [] updateCounts = b.getUpdateCounts();
            for (int  i = 0; i < updateCounts.length; i ++) {
                System.err.print(updateCounts[i] + "  ");
            }*/
        }
	
    }
    
    // Process only files under dir
    public static void visitAllFiles(File dir) throws ClassNotFoundException, SQLException, ParserConfigurationException, SAXException {
        //SAXParserFactory factory = SAXParserFactory.newInstance();
        //SAXParser parser = factory.newSAXParser();

        if (dir.isDirectory()) {
            Date start = new Date();
            String[] children = dir.list();
            double size = children.length* 1.0;
            System.out.println("Started at: "+start+" Files to process: "+size);
            for (int i=0; i<children.length; i++) {
                //System.out.println( children[i]);
                //System.out.println(new File(dir, children[i]));
                //new FileListReader( new File(dir, children[i]),db);
                System.out.println("*** Initiate processing file '"+children[i]+"' at "+new Date());
                try{
                    File current = new File(dir, children[i]);
                    InputStream uin = new FileInputStream(  current );
                    
                    if ((uin.read() != 'B') || (uin.read() != 'Z')) {
                        throw new IOException("Formato incorreto");
                    }
                    
                    CBZip2InputStream input = new CBZip2InputStream( uin );
                    FileListReader reader = new FileListReader();
                    SAXParserFactory factory = SAXParserFactory.newInstance();
                    SAXParser parser = factory.newSAXParser();
                    try {
                        parser.parse(input, reader);
                    } catch (SAXException ex) {
                        ex.printStackTrace();
                    }
                    input.close();
                    /*new UpdateFiles(db,reader.getFiles()).processFileList();
                    if(!current.delete())
                        System.out.println("Apagar: "+current);*/
                } catch (IOException e){e.printStackTrace();}
                System.out.println("*** Finnished processing file '"+children[i]+"' at "+new Date());
                System.out.println("\t*** Percentage to go: "+(i/size)*100+"%("+i+"/"+children.length+")");
                System.out.println("\t*** Num files: "+all.size()+" Free Memory:"+Runtime.getRuntime().freeMemory());
                System.gc();
                System.out.println("*** Free Memory (after GC):"+Runtime.getRuntime().freeMemory());
                
            }
            
            try {
                UpdateFiles.all.flushListToFIle();
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }/*
            try {
                UpdateFiles.DBUpdate();
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (SQLException ex) {
                ex.printStackTrace();
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
            }*/
        }
       
    }
    
   
    
    public static void main(String[] args) throws FileNotFoundException, IOException {
/*
            try {
                UpdateFiles.visitAllFiles(new File("/home/dbotelho/lists"));
            } catch (SAXException ex) {
                ex.printStackTrace();
            } catch (SQLException ex) {
                ex.printStackTrace();
            } catch (ParserConfigurationException ex) {
                ex.printStackTrace();
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
            }
*/
        //String match = "INSERT INTO \"file\" (\"file_name\",\"file_size\",\"file_TTH\",\"file_count\") VALUES ('00-talamasca_and_friends_-_made_in_trance-2004-mycel.jpg',28457,'UXPPYOIMLZSIVPMIZVNDD7OOUR2HQFQYQMJRRTA',1)";
        BufferedReader in = new BufferedReader(new FileReader("/home/dbotelho/Filelist.txt"));
        String line;
        Object[] obj = {"02-Exaile_-_Beeners-IR-CA?.mp3","18697788","54EVA2DNDXQDFSX5AURMNEKENPPA5UZEMJN2NSI",1};
        //Object[] obj = {"00-talamasca_and_friends_-_made_in_trance-2004-mycel.jpg","28457","UXPPYOIMLZSIVPMIZVNDD7OOUR2HQFQYQMJRRTA",1 };
           int count =0;
        String match = FileList.FILE_PARSER.format( obj );
        while((line = in.readLine())!= null){
            count++;
            if(line.equalsIgnoreCase(match))
                System.out.println(count+" Encontrou um match!");
        }
    
    }
    
}

class FileListReader extends DefaultHandler {
    private Stack<String> path;
    //private DataBaseManager db;
    //private String message;
    private Stack<libjdc.dc.filelist.File> files;
    
    
    /*private void printPath(){
        Iterator<String> it = path.iterator();
        System.out.print("Directory path: ");
        while(it.hasNext())
            System.out.print(it.next()+""+File.separator);
        System.out.println();
    }*/
    /** Creates a new instance of LoadCatalogo */
   /* public FileListReader(String path,DataBaseManager db) {
        this.db = db;
        try{
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            InputStream uin = new FileInputStream( new File(path ));
            if ((uin.read() != 'B') || (uin.read() != 'Z')) {
                throw new IOException("Formato incorreto");
            }
            CBZip2InputStream input = new CBZip2InputStream( uin );
            parser.parse(input, this);
            input.close();
        } catch (Exception e){e.printStackTrace();}
        
    }*/
    
    public FileListReader(/*DataBaseManager db*/){
        //this.db = db;
        files = new Stack<libjdc.dc.filelist.File>();
    }
    
   /** public FileListReader(File source,DataBaseManager db) {
        this.db = db;
        try{
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            InputStream uin = new FileInputStream( source );
            if ((uin.read() != 'B') || (uin.read() != 'Z')) {
                throw new IOException("Formato incorreto");
            }
            CBZip2InputStream input = new CBZip2InputStream( uin );
            parser.parse(input, this);
            input.close();
        } catch (Exception e){e.printStackTrace();}
        
    }*/
    
    public void startElement(String uri, String localName, String qName, Attributes attributes) 
    throws SAXException{
        
        /*if(qName.equals("FileListing")){
            this.path = new Stack<String>();
            System.out.println("Base:"+attributes.getValue("Base"));
            path.push(attributes.getValue("Base"));
        }
        
        if(qName.equals("Directory")){
            System.out.println("Name:"+attributes.getValue("Name"));
            path.push(attributes.getValue("Name"));
        }
        */
        /*if(qName.equals("File")){

            message = new String("insert into \"file\" (\"file_name\",\"file_size\",\"file_TTH\",\"file_count\") values ('"+Util.escapeString(attributes.getValue("Name"))+"',"+attributes.getValue("Size")+",'"+attributes.getValue("TTH")+"',1)");
                
            try {
                db.writeRawSql(message,true);
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
                System.out.println(message);
            } catch (SQLException ex) {
                //ex.printStackTrace();
                System.out.println("error:"+ message);
                updateFile(Util.escapeString(attributes.getValue("Name")),attributes.getValue("Size"),attributes.getValue("TTH"));
            }
        }*/
        
        if(qName.equals("File")){
            UpdateFiles.all.add(new libjdc.dc.filelist.File(Util.escapeString(attributes.getValue("Name")),attributes.getValue("Size"),attributes.getValue("TTH")));
            //getFiles().add(new dc.File(Util.escapeString(attributes.getValue("Name")),attributes.getValue("Size"),attributes.getValue("TTH")));
            //System.out.println(getFiles().size());
            /*try {
                updateFile(Util.escapeString(attributes.getValue("Name")),attributes.getValue("Size"),attributes.getValue("TTH"));
            } catch (SQLException ex) {
                ex.printStackTrace();
                message = new String("insert into \"file\" (\"file_name\",\"file_size\",\"file_TTH\",\"file_count\") values ('"+Util.escapeString(attributes.getValue("Name"))+"',"+attributes.getValue("Size")+",'"+attributes.getValue("TTH")+"',1)");
                
                try {
                    db.writeRawSql(message,true);
                } catch (UnsupportedEncodingException e) {
                   // e.printStackTrace();
                } catch (SQLException e) {
                   // e.printStackTrace();
                }
                
            }*/
            
            
            
            /// Antigo
            /*
            try {
                db.writeRawSql(message,true);
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
                System.out.println(message);
            } catch (SQLException ex) {
                //ex.printStackTrace();
                System.out.println("error:"+ message);
                updateFile(Util.escapeString(attributes.getValue("Name")),attributes.getValue("Size"),attributes.getValue("TTH"));
            }*/
        }
    }
    
    /*public void updateFile(String file_name, String file_size, String file_TTH) throws SQLException {
        ResultSet rs = null;
        String message = "SELECT * FROM \"file\" WHERE \"file_name\" LIKE '"+file_name+"' AND \"file_size\"= "+file_size+" AND \"file_TTH\" LIKE '"+file_TTH+"'";
        try {
            rs = db.getSql_stm().executeQuery(message);
            
            if (rs.next()) {
                Integer count = new Integer(rs.getString("file_count"));
                updateFile(rs.getString("file_id"),((count==null)? 1 : (count.intValue())+1));
            }
            
        } catch (SQLException se) {
            //se.printStackTrace();
            System.out.println("error: "+ message);
        }
        
    }
    
    private void updateFile(String file_id, int file_count) {
        String message = "UPDATE file SET file_count="+file_count+" WHERE file_id="+file_id;
        try {
            db.getSql_stm().executeUpdate(message);
        } catch (SQLException ex) {
            //ex.printStackTrace();
            //System.out.println(message);
        }
    }
    
    private void processFileList(){
        Iterator<dc.File> it = files.iterator();
        System.out.println("*** Start writing at DB files:"+files.size());
        while(it.hasNext()){
            dc.File current = it.next();
            try {
                updateFile(current.getName(),current.getSize(),current.getTTH());
            } catch (SQLException ex) {
                ex.printStackTrace();
                message = new String("insert into \"file\" (\"file_name\",\"file_size\",\"file_TTH\",\"file_count\") values ('"+current.getName()+"',"+current.getSize()+",'"+current.getTTH()+"',1)");
                
                try {
                    db.writeRawSql(message,true);
                } catch (UnsupportedEncodingException e) {
                   // e.printStackTrace();
                } catch (SQLException e) {
                   // e.printStackTrace();
                }
                
            }
        }
    }*/
    
    /*public void endElement(String uri, String localName, String qName) {
        if(qName.equals("Directory")){
            path.pop();
        }
    }
    
    
    public void endDocument() {
        processFileList();
    }*/

    public Stack<libjdc.dc.filelist.File> getFiles() {
        return files;
    }
    
}
